"""
词法分析器文件
"""

from tokens import *
from error import *

"""
词法分析器
"""


class Lexer:

    def __init__(self, fn, text):
        """
        :param fn:  文本的来源
        :param text: 文本的内容
        """
        self.fn = fn  # 文本的来源
        self.text = text  # 文本的内容
        self.pos = Position(-1, 0, -1, fn, text)  # 当前下标
        self.current_char = None  # 当前读到的字符
        self.advance()

    def make_tokens(self) -> (list, Error):
        """
        分割解析文本, 形成 token
        1. 遍历文本
        2. 将每一个部分解析出来
        :return: tokens 列表
        """
        tokens = []
        while self.current_char != None:
            # 空格或制表符, 不管他跳过
            if self.current_char in [' ', '\t']:
                self.advance()
            elif self.current_char in DIGITS:
                res, err = self.make_number()
                if err:
                    pos_start = self.pos.copy()
                    self.advance()
                    return [], Error(pos_start, self.pos, '解析数字类型失败', f"不是小数")
                tokens.append(res)
            elif self.current_char == '+':
                tokens.append(Token(TT_PLUS, pos_start=self.pos))
                self.advance()
            elif self.current_char == '-':
                tokens.append(Token(TT_MINUS, pos_start=self.pos))
                self.advance()
            elif self.current_char == '*':
                tokens.append(Token(TT_MUL, pos_start=self.pos))
                self.advance()
            elif self.current_char == '/':
                tokens.append(Token(TT_DIV, pos_start=self.pos))
                self.advance()
            elif self.current_char == '(':
                tokens.append(Token(TT_LPAREN, pos_start=self.pos))
                self.advance()
            elif self.current_char == ')':
                tokens.append(Token(TT_RPAREN, pos_start=self.pos))
                self.advance()
            else:
                pos_start = self.pos.copy()
                char = self.current_char
                self.advance()
                return [], IllegalCharError(pos_start, self.pos, f"'{char}'")
        tokens.append(Token(TT_EOF, pos_start=self.pos))
        return tokens, None

    def advance(self):
        """
        获取下一个字符
        :return:
        """
        self.pos.advance(self.current_char)  # self.pos.idx += 1
        if self.pos.idx < len(self.text):
            self.current_char = self.text[self.pos.idx]  # 获取下一个字符
        else:
            self.current_char = None

    def make_number(self):
        """
        解析数字类型
        注意, 该方法不能判断负数
        :return:
        """
        num_str = ''
        dot_count = 0  # 小数点数量
        pos_start = self.pos.copy()
        while self.current_char is not None and self.current_char in DIGITS + '.':
            if self.current_char == '.':
                if dot_count == 1:
                    break  # 不合法, 不可能有两个小数点
                dot_count += 1
                num_str += '.'
            else:
                num_str += self.current_char
            self.advance()  # 获取下一个字符
        if dot_count == 0:
            return Token(TT_INT, int(num_str), pos_start, self.pos), None
        else:
            return Token(TT_FLOAT, float(num_str), pos_start, self.pos), None
